package mock_seed

import (
	"errors"
	"fmt"
	"strings" // 引入 strings 包用于错误检查
	"time"
	"wms/internal/model"
	"wms/pkg/database"
	"wms/pkg/logger"

	"go.uber.org/zap"
	"gorm.io/gorm"
)

// InitSampleInventory 初始化示例库存数据（包括完整的入库示例）
func InitSampleInventory() error {
	logger.Info("开始初始化示例库存数据...")
	db := database.GetDB()

	// --- 获取必要的关联数据 ---
	var warehouses []model.Warehouse
	var suppliers []model.Supplier
	var customers []model.Customer

	if err := db.Limit(2).Find(&warehouses).Error; err != nil {
		logger.Error("获取仓库数据失败", zap.Error(err))
		return err
	}
	if err := db.Limit(2).Find(&suppliers).Error; err != nil {
		logger.Error("获取供应商数据失败", zap.Error(err))
		return err
	}
	if err := db.Limit(2).Find(&customers).Error; err != nil {
		logger.Error("获取客户数据失败", zap.Error(err))
		return err
	}
	if len(warehouses) == 0 || len(suppliers) == 0 || len(customers) == 0 {
		logger.Warn("未找到足够的仓库、供应商或客户数据，无法创建示例库存")
		return nil
	}

	// --- 按编码查找特定的货物 (增加错误处理) ---
	cargoCodesToFind := []string{"BEEF-001", "BEEF-002", "PORK-001", "PORK-002", "CHICKEN-001", "FISH-001", "SHRIMP-001", "CRAB-001"}
	var cargosMap = make(map[string]model.Cargo) // 改用 Map 存储，以 Code 为 Key
	var foundCargos []model.Cargo                // 临时存储查询结果
	if err := db.Where("code IN ?", cargoCodesToFind).Find(&foundCargos).Error; err != nil {
		logger.Error("根据编码查找货物失败", zap.Error(err))
		return err // 查询失败直接返回错误
	}
	// 将查询结果放入 Map
	for _, cargo := range foundCargos {
		cargosMap[cargo.Code] = cargo
	}

	// 检查是否所有需要的货物都找到了
	requiredCargoCount := len(cargoCodesToFind)
	if len(cargosMap) < requiredCargoCount {
		missingCodes := []string{}
		foundCodesMap := make(map[string]bool)
		for code := range cargosMap {
			foundCodesMap[code] = true
		}
		for _, code := range cargoCodesToFind {
			if !foundCodesMap[code] {
				missingCodes = append(missingCodes, code)
			}
		}
		logger.Error("未能找到所有需要的示例货物", zap.Strings("requiredCodes", cargoCodesToFind), zap.Strings("missingCodes", missingCodes), zap.Int("foundCount", len(cargosMap)))
		return fmt.Errorf("未能找到所有需要的示例货物，缺失编码: %v", missingCodes) // 明确返回错误
	}
	logger.Info("已成功查找到所有需要的示例货物", zap.Int("count", len(cargosMap)))

	// 获取仓库下的库位
	var locations []model.Location
	if err := db.Where("warehouse_id = ?", warehouses[0].ID).Limit(6).Find(&locations).Error; err != nil {
		logger.Error("获取库位数据失败", zap.Error(err))
		return err
	}
	if len(locations) < 4 { // 需要至少4个库位给第一个入库单
		logger.Warn("库位数量不足，无法创建完整示例库存")
		return nil // 或者返回错误
	}

	// 使用事务确保数据一致性
	return db.Transaction(func(tx *gorm.DB) error {
		now := time.Now()
		completedInboundCode := fmt.Sprintf("RK%s001", now.Format("20060102"))
		receivingInboundCode := fmt.Sprintf("RK%s002", now.Format("20060102"))

		// --- 创建已完成入库单及库存 ---
		var existingCompletedInbound model.InboundOrder
		if err := tx.Where("code = ?", completedInboundCode).First(&existingCompletedInbound).Error; err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				// 使用 cargosMap 中的货物创建第一个入库单
				inboundCargos1 := []model.Cargo{
					cargosMap["BEEF-001"],
					cargosMap["BEEF-002"],
					cargosMap["PORK-001"],
					cargosMap["PORK-002"],
				}
				completedInbound := createCompletedInbound(warehouses[0], suppliers[0], inboundCargos1, locations[:4], completedInboundCode)
				if err := tx.Create(&completedInbound).Error; err != nil {
					logger.Error("创建已完成入库单失败", zap.Error(err))
					return err
				}
				logger.Info("创建已完成入库单成功", zap.String("code", completedInbound.Code))

				// 创建对应的库存记录和批次记录
				for _, item := range completedInbound.Items {
					// 从 Map 中获取对应的 Cargo 对象 (保证 ID 是正确的)
					// 注意：createCompletedInbound 返回的 item.CargoID 已经是正确的 ID
					cargo, ok := findCargoByID(inboundCargos1, item.CargoID)
					if !ok {
						logger.Error("无法在 cargosMap 中找到对应的 CargoID", zap.Uint("cargoID", item.CargoID))
						return fmt.Errorf("无法在 cargosMap 中找到对应的 CargoID %d", item.CargoID)
					}

					// 获取关联货物的供应商ID
					var supplierID *uint = &suppliers[0].ID // 默认供应商
					if cargo.SupplierID != nil {
						supplierID = cargo.SupplierID
					} else {
						logger.Warn("货物未关联供应商或 SupplierID 为空，使用默认供应商", zap.String("cargoCode", cargo.Code))
					}

					// 确保 item.LocationID 不是 nil
					if item.LocationID == nil {
						logger.Error("入库单明细缺少 LocationID", zap.Uint("itemID", item.ID))
						return errors.New("入库单明细缺少 LocationID")
					}

					inventory := model.Inventory{
						CargoID:     cargo.ID, // 使用从 Map 获取的 Cargo 的真实 ID
						WarehouseID: warehouses[0].ID,
						LocationID:  *item.LocationID,
						Quantity:    item.ReceivedQuantity,
						LockStock:   0,
						MinStock:    cargo.MinStock, // 使用货物定义的 Min/Max Stock
						MaxStock:    cargo.MaxStock,
						Status:      1,
					}
					if err := tx.Create(&inventory).Error; err != nil {
						// 检查是否是唯一约束错误 (同一货物、仓库、库位已存在)
						if strings.Contains(err.Error(), "Duplicate entry") || strings.Contains(err.Error(), "UNIQUE constraint failed") {
							logger.Warn("库存记录已存在，跳过创建", zap.Uint("cargoID", cargo.ID), zap.Uint("locationID", *item.LocationID))
							// 如果记录已存在，尝试查询现有记录以获取 inventory.ID 用于创建批次
							if err := tx.Where("cargo_id = ? AND warehouse_id = ? AND location_id = ?", cargo.ID, warehouses[0].ID, *item.LocationID).First(&inventory).Error; err != nil {
								logger.Error("查询已存在的库存记录失败", zap.Error(err))
								return err // 查询失败则中断
							}
						} else {
							logger.Error("创建库存记录失败", zap.Error(err))
							return err // 其他错误则中断
						}
					}

					// 创建批次记录
					batch := model.InventoryBatch{
						InventoryID:    inventory.ID, // 使用上面创建或查询到的库存记录ID
						BatchNo:        item.BatchNo,
						Quantity:       item.ReceivedQuantity,
						ProductionDate: item.ProductionDate,
						ExpiryDate:     item.ExpiryDate,
						SupplierID:     supplierID,
						InboundOrderID: &completedInbound.ID,
						Status:         1,
						CreatedBy:      1,
						UpdatedBy:      1,
						Remark:         "冷链冻品入库批次",
					}
					if err := tx.Create(&batch).Error; err != nil {
						// 检查是否是唯一约束错误 (同一 InventoryID + BatchNo)
						if strings.Contains(err.Error(), "Duplicate entry") || strings.Contains(err.Error(), "UNIQUE constraint failed") {
							logger.Warn("批次记录已存在，跳过创建", zap.Uint("inventoryID", inventory.ID), zap.String("batchNo", item.BatchNo))
						} else {
							logger.Error("创建批次记录失败", zap.Error(err))
							return err // 其他错误则中断
						}
					}
					logger.Info(fmt.Sprintf("创建/检查 示例库存记录成功 - 货物ID: %d, 数量: %.2f, 批次: %s",
						inventory.CargoID, inventory.Quantity, batch.BatchNo))
				}
			} else {
				logger.Info("已完成入库单已存在，跳过创建", zap.String("code", completedInboundCode))
				// 保留检查并补充批次的逻辑，但确保它使用正确的 ID
				checkAndCreateMissingBatches(tx, warehouses[0].ID, suppliers[0].ID)
			}
		} else {
			logger.Info("已完成入库单已存在，跳过创建", zap.String("code", completedInboundCode))
			// 保留检查并补充批次的逻辑，但确保它使用正确的 ID
			checkAndCreateMissingBatches(tx, warehouses[0].ID, suppliers[0].ID)
		}

		// --- 创建待收货入库单 ---
		var existingReceivingInbound model.InboundOrder
		if err := tx.Where("code = ?", receivingInboundCode).First(&existingReceivingInbound).Error; err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				// 使用 cargosMap 中的货物创建第二个入库单
				// 需要确保 cargosMap 中有这些 Code
				if _, ok := cargosMap["CHICKEN-001"]; !ok {
					return errors.New("缺少货物 CHICKEN-001")
				}
				if _, ok := cargosMap["FISH-001"]; !ok {
					return errors.New("缺少货物 FISH-001")
				}
				if _, ok := cargosMap["SHRIMP-001"]; !ok {
					return errors.New("缺少货物 SHRIMP-001")
				}
				if _, ok := cargosMap["CRAB-001"]; !ok {
					return errors.New("缺少货物 CRAB-001")
				}

				inboundCargos2 := []model.Cargo{
					cargosMap["CHICKEN-001"],
					cargosMap["FISH-001"],
					cargosMap["SHRIMP-001"],
					cargosMap["CRAB-001"],
				}
				// 注意：这里没有传递库位信息，因为是待收货
				receivingInbound := createReceivingInbound(warehouses[0], suppliers[0], inboundCargos2, receivingInboundCode)
				if err := tx.Create(&receivingInbound).Error; err != nil {
					logger.Error("创建待收货入库单失败", zap.Error(err))
					return err
				}
				logger.Info("创建待收货入库单成功", zap.String("code", receivingInbound.Code))
				// 待收货状态不创建库存和批次记录
			} else {
				logger.Error("查询待收货入库单失败", zap.Error(err))
				return err
			}
		} else {
			logger.Info("待收货入库单已存在，跳过创建", zap.String("code", receivingInboundCode))
		}

		// 创建出库单样例数据
		if err := createSampleOutboundOrders(tx, warehouses[0], customers[0], cargosMap); err != nil {
			logger.Error("创建出库单样例数据失败", zap.Error(err))
			return err
		}

		logger.Info("示例库存数据初始化事务完成")
		return nil
	})
}

// 辅助函数：根据ID在 Cargo slice 中查找 Cargo (因为 Map 是按 Code 存的)
func findCargoByID(cargos []model.Cargo, id uint) (model.Cargo, bool) {
	for _, c := range cargos {
		if c.ID == id {
			return c, true
		}
	}
	return model.Cargo{}, false
}

// 辅助函数：检查并为没有批次的库存创建批次 (如果入库单已存在)
func checkAndCreateMissingBatches(tx *gorm.DB, warehouseID uint, defaultSupplierID uint) {
	var inventoriesToCheck []model.Inventory
	if err := tx.Where("warehouse_id = ?", warehouseID).Find(&inventoriesToCheck).Error; err == nil {
		logger.Info("检查需要补充批次的库存记录...", zap.Int("count", len(inventoriesToCheck)))
		for _, inventory := range inventoriesToCheck {
			var batchCount int64
			if err := tx.Model(&model.InventoryBatch{}).Where("inventory_id = ?", inventory.ID).Count(&batchCount).Error; err == nil && batchCount == 0 {
				logger.Warn("库存记录缺少批次，尝试补充", zap.Uint("inventoryID", inventory.ID), zap.Uint("cargoID", inventory.CargoID))
				var cargo model.Cargo
				// 查询货物以获取供应商ID
				if err := tx.First(&cargo, inventory.CargoID).Error; err == nil {
					var supplierID *uint
					if cargo.SupplierID != nil {
						supplierID = cargo.SupplierID
					} else {
						supplierID = &defaultSupplierID // 使用默认
					}
					now := time.Now()
					productionDate := now.Add(-30 * 24 * time.Hour)
					expiryDate := now.Add(180 * 24 * time.Hour)
					batch := model.InventoryBatch{
						InventoryID:    inventory.ID,
						BatchNo:        fmt.Sprintf("SUPPL%s%03d", now.Format("0102"), inventory.ID), // 生成补充批次号
						Quantity:       inventory.Quantity,                                           // 假设批次数量等于当前库存量
						ProductionDate: &productionDate,
						ExpiryDate:     &expiryDate,
						SupplierID:     supplierID,
						// InboundOrderID: ? // 无法确定关联的入库单
						Status:    1,
						CreatedBy: 1,
						UpdatedBy: 1,
						Remark:    "补充的冷链批次信息(seed)",
					}
					if err := tx.Create(&batch).Error; err != nil {
						// 检查是否是唯一约束错误
						if strings.Contains(err.Error(), "Duplicate entry") || strings.Contains(err.Error(), "UNIQUE constraint failed") {
							logger.Warn("补充批次时发现已存在，跳过", zap.Uint("inventoryID", inventory.ID), zap.String("batchNo", batch.BatchNo))
						} else {
							logger.Error("补充创建批次记录失败", zap.Error(err))
						}
					} else {
						logger.Info(fmt.Sprintf("补充创建批次记录成功 - 库存ID: %d, 批次: %s", inventory.ID, batch.BatchNo))
					}
				} else {
					logger.Error("补充批次时查询货物信息失败", zap.Uint("cargoID", inventory.CargoID), zap.Error(err))
				}
			}
		}
	} else {
		logger.Error("补充批次检查时查询库存记录失败", zap.Error(err))
	}
}

// 创建一个已完成的入库单
func createCompletedInbound(warehouse model.Warehouse, supplier model.Supplier, cargos []model.Cargo, locations []model.Location, code string) model.InboundOrder {
	now := time.Now()
	yesterdayTime := now.Add(-24 * time.Hour)

	inbound := model.InboundOrder{
		Code:          code,
		Type:          1, // 采购入库
		WarehouseID:   warehouse.ID,
		SupplierID:    &supplier.ID,
		ExpectedTime:  &yesterdayTime,
		OrderNo:       fmt.Sprintf("CG%s001", now.Format("20060102")),
		Note:          "冷链肉类冻品采购入库，需保持-18℃低温环境",
		Status:        model.StatusInboundCompleted, // 已完成
		UserID:        1,                            // 管理员
		ApproveUserID: pointerUint(1),
		ApproveTime:   &yesterdayTime,
		ApproveNote:   "冷链肉类验收无异常",
		ReceiveUserID: pointerUint(1),
		ReceiveTime:   &yesterdayTime,
		PutawayUserID: pointerUint(1),
		PutawayTime:   &yesterdayTime,
		CreatedAt:     yesterdayTime,
		UpdatedAt:     now,
	}

	items := make([]*model.InboundOrderItem, 0, len(cargos))
	for i, cargo := range cargos {
		// 确保 locations 足够多
		if i >= len(locations) {
			logger.Warn("提供的库位数量不足，部分入库明细将没有库位信息", zap.Int("cargoIndex", i), zap.Int("locationCount", len(locations)))
			continue // 或者分配一个默认库位？这里选择跳过
		}
		locationID := locations[i].ID
		receivedQty := float64(15 + i*5) // 示例数量

		// 示例批次信息
		productionDate := now.AddDate(0, -2, -1)                     // 生产日期：2个月前
		expiryDate := now.AddDate(0, 6, -1)                          // 过期日期：6个月后
		batchNo := fmt.Sprintf("LOT%s%03d", now.Format("0421"), i+1) // 批次号：LOTMMDDXXX

		items = append(items, &model.InboundOrderItem{
			// InboundOrderID 会在 GORM 创建时自动填充
			CargoID:          cargo.ID, // 使用传入的 Cargo 的真实 ID
			Quantity:         receivedQty,
			ReceivedQuantity: receivedQty,
			PutawayQuantity:  receivedQty,       // 已完成状态，已上架数量等于实收数量
			UnitPrice:        cargo.Price * 0.9, // 假设采购价是售价的9折
			BatchNo:          batchNo,
			ProductionDate:   &productionDate,
			ExpiryDate:       &expiryDate,
			LocationID:       &locationID, // 关联库位 ID
			Note:             fmt.Sprintf("%s 入库", cargo.Name),
			// Cargo 字段在 GORM 关联中通常不需要手动填充，ID 足够
			// Cargo:            &cargo,
		})
	}
	inbound.Items = items
	return inbound
}

// 创建一个待收货的入库单
func createReceivingInbound(warehouse model.Warehouse, supplier model.Supplier, cargos []model.Cargo, code string) model.InboundOrder {
	now := time.Now()
	approveTime := now.Add(-2 * time.Hour)  // 2小时前审核
	expectedTime := now.Add(24 * time.Hour) // 预计1天后到货

	inbound := model.InboundOrder{
		Code:          code,
		Type:          1, // 采购入库
		WarehouseID:   warehouse.ID,
		SupplierID:    &supplier.ID,
		ExpectedTime:  &expectedTime,
		OrderNo:       fmt.Sprintf("CG%s002", now.Format("20060102")),
		Note:          "冷链冻品采购，请注意查收",
		Status:        model.StatusInboundWaitingReceive, // 待收货
		UserID:        1,                                 // 管理员
		ApproveUserID: pointerUint(1),                    // 审核人ID
		ApproveTime:   &approveTime,                      // 审核时间
		ApproveNote:   "审核通过",
		CreatedAt:     now.Add(-3 * time.Hour), // 3小时前创建
		UpdatedAt:     now,
	}

	items := make([]*model.InboundOrderItem, 0, len(cargos))
	for _, cargo := range cargos {
		quantity := float64(10) // 简化为固定数量
		items = append(items, &model.InboundOrderItem{
			CargoID:   cargo.ID,
			Quantity:  quantity,          // 应收数量
			UnitPrice: cargo.Price * 0.9, // 采购价是售价的9折
			Note:      cargo.Name,
		})
	}
	inbound.Items = items
	return inbound
}

// 辅助函数，返回 uint 指针
func pointerUint(v uint) *uint {
	return &v
}

// createSampleOutboundOrders 创建出库单样例数据
func createSampleOutboundOrders(tx *gorm.DB, warehouse model.Warehouse, customer model.Customer, cargosMap map[string]model.Cargo) error {
	logger.Info("开始创建出库单样例数据...")

	// 只创建待拣货状态的出库单
	now := time.Now()
	timeFormat := now.Format("20060102")

	// 创建待拣货出库单
	pickingCode := fmt.Sprintf("CK%s001", timeFormat)
	var existingPicking model.OutboundOrder
	if err := tx.Where("code = ?", pickingCode).First(&existingPicking).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			// 待拣货出库单
			picking := createPickingOutbound(warehouse, customer, []model.Cargo{
				cargosMap["BEEF-001"],
				cargosMap["PORK-001"],
			}, pickingCode)

			if err := tx.Create(&picking).Error; err != nil {
				logger.Error("创建待拣货出库单失败", zap.Error(err))
				return err
			}
			logger.Info("创建待拣货出库单成功", zap.String("code", picking.Code))
		} else {
			logger.Error("查询出库单失败", zap.Error(err))
			return err
		}
	} else {
		logger.Info("出库单已存在，跳过创建", zap.String("code", pickingCode))
	}

	return nil
}

// createPickingOutbound 创建待拣货出库单
func createPickingOutbound(warehouse model.Warehouse, customer model.Customer, cargos []model.Cargo, code string) model.OutboundOrder {
	now := time.Now()
	approveTime := now.Add(-1 * time.Hour) // 1小时前审核

	// 创建出库单
	outbound := model.OutboundOrder{
		Code:          code,
		Type:          1, // 1=销售出库
		WarehouseID:   warehouse.ID,
		CustomerID:    pointerUint(customer.ID),
		OrderNo:       fmt.Sprintf("SO%s%03d", now.Format("20060102"), 2),
		Status:        model.StatusOutboundWaitingPicking, // 待拣货
		Note:          "冷链冻品销售出库",
		CreatedAt:     now.Add(-2 * time.Hour), // 2小时前创建
		UpdatedAt:     now,
		UserID:        1,                        // 创建人ID
		ApproveUserID: pointerUint(1),           // 审核人ID
		ApproveTime:   pointerTime(approveTime), // 1小时前审核
		Items:         []*model.OutboundOrderItem{},
	}

	// 添加出库单明细
	for i, cargo := range cargos {
		expectedQty := float64(5) // 简化为固定数量
		item := &model.OutboundOrderItem{
			OutboundOrderID: 0, // 创建后会自动填充
			CargoID:         cargo.ID,
			Quantity:        expectedQty,
			PickedQuantity:  0, // 未拣货
			ShippedQuantity: 0, // 未发货
			Note:            cargo.Name,
			BatchNo:         fmt.Sprintf("B%s%03d", now.Format("20060102"), i+1),
			CreatedAt:       now.Add(-2 * time.Hour),
			UpdatedAt:       now,
		}
		outbound.Items = append(outbound.Items, item)
	}

	return outbound
}

// pointerTime 将time.Time转为指针
func pointerTime(t time.Time) *time.Time {
	return &t
}
